package com.cjkj.equipment.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.cjkj.common.core.constant.*;
import com.cjkj.common.core.domain.R;
import com.cjkj.common.core.exception.ServiceException;
import com.cjkj.common.core.utils.StringUtils;
import com.cjkj.common.core.utils.bean.BeanUtils;
import com.cjkj.equipment.domain.MonitorPadData;
import com.cjkj.equipment.domain.TEquipmentInfo;
import com.cjkj.equipment.domain.TWarnRecords;
import com.cjkj.equipment.domain.TWarnSetting;
import com.cjkj.equipment.domain.dto.BreathAndHeartAVGDto;
import com.cjkj.equipment.domain.dto.MonitorPadDto;
import com.cjkj.equipment.mapper.MonitorPadDataMapper;
import com.cjkj.equipment.mapper.TEquipmentInfoMapper;
import com.cjkj.equipment.mapper.TWarnSettingMapper;
import com.cjkj.equipment.service.ITWarnRecordsService;
import com.cjkj.equipment.service.MonitorPadDataService;
import com.cjkj.equipment.service.PatientSleepStageRecordService;
import com.cjkj.equipment.utils.SleepStageUtil;
import com.cjkj.system.api.RemoteHospitalEquipmentService;
import com.cjkj.system.api.domain.APIEquipmentUsageRecords;
import com.cjkj.system.api.domain.APIMonitorPadData;
import com.cjkj.system.api.domain.PatientSleepStageRecord;
import com.cjkj.system.api.domain.dto.APIEquipmentStatusDto;
import com.cjkj.system.api.domain.request.EquipmentHDAReq;
import com.cjkj.system.api.domain.request.PatientEquipmentRTDReq;
import com.cjkj.system.api.domain.request.RecordsReq;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.jms.Message;
import java.util.*;

/**
 *
 */
@Service
@Slf4j
public class MonitorPadDataServiceImpl implements MonitorPadDataService {

    @Resource
    private RemoteHospitalEquipmentService remoteHospitalEquipmentService;
    @Resource
    private PatientSleepStageRecordService sleepStageRecordService;
    @Resource
    private TWarnSettingMapper tWarnSettingMapper;
    @Resource
    private ITWarnRecordsService recordsService;
    @Resource
    private MonitorPadDataMapper monitorPadDataMapper;
    @Resource
    private TEquipmentInfoMapper equipmentInfoMapper;

    @Override
    public void insertData(MonitorPadData monitorPadData) {
        monitorPadData.setEquipmentType(EquipmentConstants.EQUIPMENT_TYPE_MONITOR_PAD);
        int insert = monitorPadDataMapper.insertMonitorPadData(monitorPadData);
        if (insert < 1){
            log.error(monitorPadData.getEquipmentNo()+":"+monitorPadData.getAcquisitionTime()+"数据插入失败");
            throw new ServiceException("插入数据失败！");
        }
    }

    @Override
    public MonitorPadData getLastByTimeRange(String equipmentNo, Date startTime, Date endTime) {
        return monitorPadDataMapper.getLastByTimeRange(equipmentNo,startTime,endTime);
    }

    /**
     * 1.查询患者设备使用记录，当前设备属于谁在使用
     * //2.创建或者更新报告
     * 3.更新状态变化记录表
     * 4.插入采集到的数据
     * */
    @Override
    public void processMessage(Message message) {
        byte[] body;
        try {
            body = message.getBody(byte[].class);
        } catch (Exception e){
            log.error("processMessage occurs error ", e);
            throw new ServiceException("数据采集失败："+e);
        }
        String content = new String(body);
        MonitorPadDto monitorPadDto = JSONObject.parseObject(content, MonitorPadDto.class);
        MonitorPadData data = getDataFromDto(monitorPadDto);

        // 设备号
        String equipmentNo = data.getEquipmentNo();

        // 查询是否系统的设备
        TEquipmentInfo equipmentInfo = equipmentInfoMapper.selectEquipment(EquipmentConstants.EQUIPMENT_TYPE_MONITOR_PAD_TYPE, equipmentNo);
        if(equipmentInfo == null) {
            // 不存在，说明是其他系统的设备，数据存入monitor_pad_data_other
            data.setEquipmentType(EquipmentConstants.EQUIPMENT_TYPE_MONITOR_PAD);
            monitorPadDataMapper.insertOther(data);
            return ;
        }
        log.warn(content);

        // 睡眠分期
        fmtSleepStageData(data);
        // 监测数据存入数据库
        insertData(data);
        // 修改设备状态
        updateStatus(equipmentInfo.getId(), data);
        // 判断及保存预警信息
        judgeWarn(data);
    }

    /**
     * 计算睡眠分期
     * 保存睡眠分期数据
     *
     * @param data
     */
    private void fmtSleepStageData(MonitorPadData data){
        // 监测时间
        Date acquisitionTime = data.getAcquisitionTime();
        // 设备号
        String equipmentNo = data.getEquipmentNo();

        // 计算睡眠状态（为了后面查询静息心率）
        Calendar myCalendar = new GregorianCalendar();
        myCalendar.setTime(SleepStageUtil.getReportDay(acquisitionTime));
        myCalendar.set(Calendar.HOUR_OF_DAY, 18);
        myCalendar.set(Calendar.MINUTE,0);
        myCalendar.set(Calendar.SECOND,0);
        Date reportStartTime = myCalendar.getTime();
        myCalendar.add(Calendar.DAY_OF_MONTH,1);
        myCalendar.set(Calendar.HOUR_OF_DAY, 8);
        myCalendar.set(Calendar.MINUTE,0);
        myCalendar.set(Calendar.SECOND,0);
        Date reportEndTime = myCalendar.getTime();

        // 监测数据的时间在睡眠报告时间范围（18:00-08:00）内的，计算睡眠分期状态
        if(acquisitionTime.getTime() >= reportStartTime.getTime() && acquisitionTime.getTime() <= reportEndTime.getTime()) {
            // 查询最后一条数据
            MonitorPadData lastData = getLastByTimeRange(equipmentNo, reportStartTime, reportEndTime);
            if(lastData != null) {
                try {
                    // 查询前25条在床数据作为基准数据
                    List<MonitorPadData> benchmarkData = monitorPadDataMapper.getEquipmentNodata25(equipmentNo, reportStartTime);
                    // 基准数据是否为空
                    boolean dataIsEmpty = StringUtils.isNull(benchmarkData) || benchmarkData.isEmpty();

                    BreathAndHeartAVGDto avgDto = null;
                    if(! dataIsEmpty) {
                        // 算出基准数据心率和呼吸的平均值
                        avgDto = SleepStageUtil.calculateAVG(benchmarkData);
                    }

                    if(SleepConstants.SLEEP_STATUS_IN_BED.equals(data.getSleepStatus())){
                        // 如果接收的数据的状态是在床
                        if(dataIsEmpty){
                            // 如果查询的基准数据为空，设置这条数据是浅睡
                            data.setSleepStage(SleepConstants.SLEEP_STAGE_WIDE_AWAKE);
                        } else {
                            // 计算出睡眠分期状态
                            String sleepStage = SleepStageUtil.calculateSleepStage(avgDto.getHeartRateAvg(), data.getHeartRate(),
                                    avgDto.getBreathRateAvg(), data.getBreathRate(), data.getBodyMove());
                            data.setSleepStage(sleepStage);
                        }
                    }
                    // 弃用（2023-12-08）
//                    updateSleepStatusRecord(lastData,data);

                    if (! dataIsEmpty && benchmarkData.size() == 25) {
                        // 计算睡眠分期数据
                        inertSleepStageData(equipmentNo, benchmarkData, avgDto, reportEndTime);
                    }

                }catch (Exception e){
                    log.error(e.getMessage());
                }
            }
        }

    }

    @Override
    public List<MonitorPadData> listData(RecordsReq req) {
        return monitorPadDataMapper.listDataByEquipment(req);
    }

    @Override
    public Map<String, Object> appListData(EquipmentHDAReq req) {

        Integer pageNum = req.getPageNum();
        Integer pageSize = req.getPageSize();
        if (pageSize == null || pageNum == null) {
            pageNum = 1;
            pageSize = 25;
        }
        // 查询数据
        PageHelper.startPage(pageNum, pageSize);
        List<MonitorPadData> monitorPadData = monitorPadDataMapper.appListData(req);
        PageInfo<MonitorPadData> pageInfo = new PageInfo<>(monitorPadData);
        List<MonitorPadData> records = pageInfo.getList();

        List<APIMonitorPadData> resultList = new ArrayList<>();
        records.forEach(e->{
            APIMonitorPadData apiMonitorPadData = new APIMonitorPadData();
            BeanUtils.copyProperties(e,apiMonitorPadData);
            resultList.add(apiMonitorPadData);
        });

        Map<String, Object> result = new HashMap<>();
        result.put("data", resultList);
        result.put("total", pageInfo.getTotal());
        return result;
    }

    /** 判断异常并记录
     * 1.获取当前全部预警设置；
     * 2.遍历全部设置，并查询该设备得使用记录
     *  a.有人使用，判断是否满足预警条件，满足进行记录；
     *  b.无人使用，直接返回
     * */
    @Override
    public void judgeWarn(MonitorPadData data){
        if(data == null) {
            return ;
        }
        // 查询使用记录
        R<APIEquipmentUsageRecords> resultRecords = remoteHospitalEquipmentService.getRecordsByEquipment(data.getEquipmentNo(), SecurityConstants.INNER);
        if(HttpStatus.SUCCESS != resultRecords.getCode() || resultRecords.getData() == null){
            return ;
        }

        // 预警信息
        List<JSONObject> objects = new ArrayList<>();

        // 查询并遍历预警设置
        List<TWarnSetting> warnSettings = tWarnSettingMapper.selectTWarnSettingList(new TWarnSetting());
        warnSettings.forEach( e -> {
            String warnType = e.getWarnType();
            if(SleepConstants.SLEEP_STATUS_IN_BED.equals(data.getSleepStatus())){
                // 呼吸率预警
                if(WarnConstants.WARN_TYPE_BREATH.equals(warnType)){
                    Integer breathRate = data.getBreathRate();
                    String content = "";
                    if(null != breathRate && breathRate < e.getLowerLimit()){
                        content = WarnConstants.WARN_CONTENT_BREATH_LOW;
                    }
                    if(null != breathRate && breathRate > e.getUpperLimit()){
                        content = WarnConstants.WARN_CONTENT_BREATH_HIGH;
                    }
                    if(StringUtils.isNotBlank(content)) {
                        JSONObject object = new JSONObject();
                        object.put("content", content);
                        object.put("value", null == breathRate ?"0": breathRate);
                        object.put("warnType", warnType);
                        objects.add(object);
                    }
                }
                // 心率预警
                if(WarnConstants.WARN_TYPE_HEART.equals(warnType)){
                    Integer heartRate = data.getHeartRate();
                    String content = "";
                    if(null != heartRate && heartRate < e.getLowerLimit()){
                        content = WarnConstants.WARN_CONTENT_HEART_LOW;
                    }
                    if(null != heartRate && heartRate > e.getUpperLimit()){
                        content = WarnConstants.WARN_CONTENT_HEART_HIGH;
                    }
                    if(StringUtils.isNotBlank(content)) {
                        JSONObject object = new JSONObject();
                        object.put("content", content);
                        object.put("value", null == heartRate ?"0": heartRate);
                        object.put("warnType", warnType);
                        objects.add(object);
                    }
                }
                // 血氧预警
                if(WarnConstants.WARN_TYPE_SPO2.equals(warnType)){
                    Integer spo2 = data.getSpo2();
                    String content = "";
                    if(null != spo2 && spo2 < e.getLowerLimit()){
                        content = WarnConstants.WARN_CONTENT_SPO2_LOW;
                    }
                    if(null != spo2 && spo2 > e.getUpperLimit()){
                        content = WarnConstants.WARN_CONTENT_SPO2_HIGH;
                    }
                    if(StringUtils.isNotBlank(content)) {
                        JSONObject object = new JSONObject();
                        object.put("content", content);
                        object.put("value", null == spo2 ?"0": spo2);
                        object.put("warnType", warnType);
                        objects.add(object);
                    }
                }
            }
        });

        // 如果预警信息不为空，批量添加预警信息
        if(! objects.isEmpty()){
            // 预警记录
            List<TWarnRecords> recordsList = new ArrayList<>();
            // 使用记录
            APIEquipmentUsageRecords record = resultRecords.getData();
            for (JSONObject warn : objects) {
                TWarnRecords warnRecord = new TWarnRecords();
                warnRecord.setHospitalId(record.getHospitalId());
                warnRecord.setDeptId(record.getDeptId());
                warnRecord.setVisitNo(record.getVisitNo());
                warnRecord.setEquipmentNo(data.getEquipmentNo());
                warnRecord.setCreateTime(data.getAcquisitionTime());
                warnRecord.setHasHandle(WarnConstants.WARN_HANDLE_UNPROCESSED);
                warnRecord.setNextReminderTime(new Date());
                warnRecord.setWarnType(warn.getString("warnType"));
                warnRecord.setWarnContent(warn.getString("content"));
                warnRecord.setWarnValue(warn.getString("value"));

                recordsList.add(warnRecord);
            }

            if(!recordsService.saveOrUpdateRecord(recordsList)){
                log.error("异常记录保存或更新失败"+data.getEquipmentNo() + ":" + data.getAcquisitionTime());
            }
        }
    }

    private void updateSleepStatusRecord(MonitorPadData lastData,MonitorPadData data){
        PatientSleepStageRecord sleepStageRecord = new PatientSleepStageRecord();
        sleepStageRecord.setEquipmentNo(data.getEquipmentNo());
        sleepStageRecord.setAcquisitionTime(data.getAcquisitionTime());
        if(StringUtils.isNull(lastData)){
            sleepStageRecord.setSleepStage(data.getSleepStatus());
            sleepStageRecordService.insertRecord(sleepStageRecord);
        }else if(SleepConstants.SLEEP_STATUS_IN_BED.equals(data.getSleepStatus())){
            if(data.getSleepStage() != null){
                if(!data.getSleepStage().equals(lastData.getSleepStage())){
                    sleepStageRecord.setSleepStage(data.getSleepStage());
                    sleepStageRecordService.insertRecord(sleepStageRecord);
                }
            }
        }else {
            if(!data.getSleepStatus().equals(lastData.getSleepStatus())){
                sleepStageRecord.setSleepStage(data.getSleepStatus());
                sleepStageRecordService.insertRecord(sleepStageRecord);
            }
        }

    }

    /**
     * @Description: 将接收到的数据赋值到对象上
     * @Creator: 93000
     * @Date: 2022/11/7 9:24
     * @Param:
     * @return:
     */
    private MonitorPadData getDataFromDto(MonitorPadDto dto){
        MonitorPadData data = new MonitorPadData();
        data.setEquipmentNo(dto.getEquipmentNo());
        data.setProductKey(dto.getProductKey());
        data.setCreateTime(new Date());
        if(dto.getItems().getBreathRate() != null){
            data.setBreathRate(Integer.parseInt(dto.getItems().getBreathRate().getValue()));
            data.setAcquisitionTime(dto.getItems().getBreathRate().getTime());
        }
        if(dto.getItems().getHeartRate() != null){
            data.setHeartRate(Integer.parseInt(dto.getItems().getHeartRate().getValue()));
            data.setAcquisitionTime(dto.getItems().getHeartRate().getTime());
        }
        if(dto.getItems().getSpo2() != null){
            data.setSpo2(Integer.parseInt(dto.getItems().getSpo2().getValue()));
            data.setAcquisitionTime(dto.getItems().getSpo2().getTime());
        }
        if(dto.getItems().getBodyMove() != null){
            data.setBodyMove(dto.getItems().getBodyMove().getValue());
            data.setAcquisitionTime(dto.getItems().getBodyMove().getTime());
        }
        if(dto.getItems().getSleepStatus() != null){
            data.setSleepStatus(dto.getItems().getSleepStatus().getValue());
            data.setAcquisitionTime(dto.getItems().getSleepStatus().getTime());
        }
        if(dto.getItems().getEquipmentFailure() != null){
            data.setEquipmentFailure(dto.getItems().getEquipmentFailure().getValue());
            data.setAcquisitionTime(dto.getItems().getEquipmentFailure().getTime());
        }
        return data;
    }

    @Override
    public MonitorPadData getLastDataOnUse(PatientEquipmentRTDReq req) {
        return monitorPadDataMapper.selectLastDataOnUse(req);
    }

    @Override
    public void inertSleepStageData(String equipmentNo, List<MonitorPadData> benchmarkData, BreathAndHeartAVGDto avgDto, Date reportEndTime){
        // 取出基准数据最后一个时间，在数据库进行查询，是否有这个时间点的数据，有就说明此状态已经插入数据库了
        Date lastBenchmarkDataTime = benchmarkData.get(24).getAcquisitionTime();
        MonitorPadData lastTimeInitData = monitorPadDataMapper.getEquipmentNodatachushi(equipmentNo, lastBenchmarkDataTime);
        if (lastTimeInitData == null) {
            // 基准数据的第一条数据的时间
            Date firstBenchmarkDataTime = benchmarkData.get(0).getAcquisitionTime();
            // 基准数据的第二条数据的时间
            Date secondBenchmarkDataTime = benchmarkData.get(1).getAcquisitionTime();

            // 如果第二条数据比第一条间隔了十分钟以上，则按照第二条数据的时间为上床时间
            long differMillisecond = secondBenchmarkDataTime.getTime() - firstBenchmarkDataTime.getTime();
            Date firstTime = differMillisecond > 10 * 60 * 1000 ? secondBenchmarkDataTime: firstBenchmarkDataTime;
            // 插入初始数据
            MonitorPadData firstTimeInitData = monitorPadDataMapper.getEquipmentNodatachushi(equipmentNo, firstTime);
            if(firstTimeInitData == null) {
                monitorPadDataMapper.insertchushi(equipmentNo, firstTime, SleepConstants.SLEEP_STATUS_OUT_BED);
                monitorPadDataMapper.insertchushi(equipmentNo, lastBenchmarkDataTime, SleepConstants.SLEEP_STATUS_IN_BED);
            }
        }

        // 取出monitor_pad_data表的最后一条数据的监测时间
        Date lastMonitorAcquisitionTime = monitorPadDataMapper.getLastmonit(equipmentNo, lastBenchmarkDataTime, reportEndTime).getAcquisitionTime();

        // 取出patient_sleep_stage_record_temp表的最后一条数据的监测时间
        Date lastTempDataAcquisitionTime = monitorPadDataMapper.getLastTemp(equipmentNo, lastBenchmarkDataTime, reportEndTime).getAcquisitionTime();

        // 区间数据
        List<MonitorPadData> intervalDataList;
        Date interval10minute = null;
        // 最后一条数据采集时间比最后一条患者睡眠分期状态变化时间大于等于10分钟时
        long l = (lastMonitorAcquisitionTime.getTime() - lastTempDataAcquisitionTime.getTime()) / 1000 / 60;
        // 最后一条patient_sleep_stage_record_temp睡觉状态数据时间后的20分钟
        Calendar lastTempTimeCal = new GregorianCalendar();
        lastTempTimeCal.setTime(lastTempDataAcquisitionTime);
        lastTempTimeCal.add(Calendar.MINUTE, 20);
        Date lastTempTimeCalTime = lastTempTimeCal.getTime();

        if (l >= 10) {
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(lastTempDataAcquisitionTime);
            calendar.add(Calendar.MINUTE, 10);
            interval10minute = calendar.getTime();
            // 查询最后一条患者睡眠分期状态变化时间 到 最后一条患者睡眠分期状态变化时间的当天十点钟 这区间的睡眠垫采集数据
            intervalDataList = monitorPadDataMapper.qjdata(equipmentNo, lastTempDataAcquisitionTime, interval10minute);

            // 没数据，添加为离床状态
            if(intervalDataList.isEmpty()) {
                monitorPadDataMapper.insertchushi(equipmentNo, interval10minute, SleepConstants.SLEEP_STATUS_OUT_BED);
                return ;
            }
        }
        else if (l > 0 && (reportEndTime.getTime() <= lastTempTimeCalTime.getTime() || System.currentTimeMillis() > lastTempTimeCalTime.getTime())){
            // 当前系统时间大于最后一条patient_sleep_stage_record_temp睡觉状态数据时间后的20分钟
            intervalDataList = monitorPadDataMapper.qjdata(equipmentNo, lastTempDataAcquisitionTime, lastMonitorAcquisitionTime);
        }
        else {
            return ;
        }

        // 区间数据中在床心率总和、呼吸率总和
        int inBedHeartRateSum = 0;
        int inBedBreathRateSum = 0;
        // 区间数据中在床次数
        int inBedCount = 0;
        // 区间数据中是否存在体动，默认无
        String bodeMove = SleepConstants.SLEEP_BODYMOVE_FALSE;

        Date lasttime = null;
        Date last4time = null;
        int jh = 1;
        // 离床后回来的状态
        MonitorPadData returnBedFirstData = null;
        for (int i = 0; i < intervalDataList.size(); i ++) {
            MonitorPadData intervalDataObj = intervalDataList.get(i);
            if (SleepConstants.SLEEP_STATUS_OUT_BED.equals(intervalDataObj.getSleepStatus())) {
                // 离床
                jh = i;
                if (i == 0) {
                    lasttime = intervalDataObj.getAcquisitionTime();
                }
                last4time = intervalDataObj.getAcquisitionTime();
                if (intervalDataList.size() != i + 1) {
                    returnBedFirstData = intervalDataList.get(i + 1);
                }
                break;
            } else {
                inBedHeartRateSum += intervalDataObj.getHeartRate();
                inBedBreathRateSum += intervalDataObj.getBreathRate();
                inBedCount += 1;

                if (SleepConstants.SLEEP_BODYMOVE_TRUE.equals(intervalDataObj.getBodyMove())) {
                    bodeMove = SleepConstants.SLEEP_BODYMOVE_TRUE;
                }

                lasttime = intervalDataObj.getAcquisitionTime();
            }
        }

        // 区间数据中在床平均心率值、平均呼吸率值
        int avgHeart = inBedCount == 0 ? 0 : inBedHeartRateSum / inBedCount;
        int avgBreath = inBedCount == 0 ? 0 : inBedBreathRateSum / inBedCount;
        // 区间数据的睡眠分期状态
        String sleepStage = SleepStageUtil.calculateSleepStage(avgDto.getHeartRateAvg(), avgHeart, avgDto.getBreathRateAvg(), avgBreath, bodeMove);
        if (lasttime == null) {
            lasttime = interval10minute;
            sleepStage = SleepConstants.SLEEP_STATUS_OUT_BED;
        }
        if (jh != 0) {
            monitorPadDataMapper.insertchushi(equipmentNo, lasttime, sleepStage);
        }
        if (last4time != null) {
            monitorPadDataMapper.insertchushi(equipmentNo, last4time, SleepConstants.SLEEP_STATUS_OUT_BED);

            // 计算回来后的第一个状态
            if (returnBedFirstData != null) {
                sleepStage = SleepStageUtil.calculateSleepStage(avgDto.getHeartRateAvg(), returnBedFirstData.getHeartRate(),
                        avgDto.getBreathRateAvg(), returnBedFirstData.getBreathRate(),
                        returnBedFirstData.getBodyMove());
                if (SleepConstants.SLEEP_STATUS_OUT_BED.equals(returnBedFirstData.getSleepStatus())) {
                    // 离床
                    sleepStage = SleepConstants.SLEEP_STATUS_OUT_BED;
                }
                monitorPadDataMapper.insertchushi(equipmentNo, returnBedFirstData.getAcquisitionTime(), sleepStage);
            }
        }
    }

    @Override
    public void doSaveData(List<MonitorPadData> benchmarkData) {
        try {
            for (MonitorPadData padData : benchmarkData) {
                // 计算睡眠分期
                fmtSleepStageData(padData);
                // 监测数据存入数据库
                insertData(padData);
                Thread.sleep(2000L);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void updateStatus(String equipmentId, MonitorPadData data){
        APIEquipmentStatusDto equipmentStatusDto = new APIEquipmentStatusDto();
        equipmentStatusDto.setEquipmentId(equipmentId);
        equipmentStatusDto.setFailureFlag(data.getEquipmentFailure());
        equipmentStatusDto.setFailureTime(data.getAcquisitionTime());
        remoteHospitalEquipmentService.updateEquipmentStatus(equipmentStatusDto, SecurityConstants.INNER);
    }
}




